package com.tangyuan.user.authRedirect;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.ContentType;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.ijpay.core.kit.WxPayKit;
import com.tangyuan.common.config.WxPayConfig;
import com.tangyuan.dto.CallBackDto;
import com.tangyuan.feignapis.video.IVideoHotFeignClient;
import com.tangyuan.model.TyFinance;
import com.tangyuan.model.UserBalance;
import com.tangyuan.model.VideoHot;
import com.tangyuan.model.activity.Enroll;
import com.tangyuan.common.config.AlipayConfig;
import com.tangyuan.model.activity.EnrollRecord;
import com.tangyuan.model.activity.TicketTypeRecord;
import com.tangyuan.user.mapper.*;
import com.tangyuan.wx.WxDto;
import com.tangyuan.wx.WxPayDto;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Validated
@RestController
@RequestMapping("/user")
@Slf4j
public class AliNotify {

    @Autowired
    private TyFinanceMapper tyFinanceMapper;
    @Autowired
    private UserBalanceMapper userBalanceMapper;
    @Autowired
    private EnrollMapper enrollMapper;
    @Autowired
    private EnrollRecordMapper enrollRecordMapper;

    @Autowired
    private TicketTypeRecordMapper ticketTypeRecordMapper;

    @Autowired
    private IVideoHotFeignClient videoFeignClient;

    /**
     * 支付宝支付成功后.异步请求该接口
     *
     * @param request
     * @return
     * @throws IOException
     */
    @RequestMapping(value = "/alipay/authRedirect", method = RequestMethod.POST)
    @Transactional(rollbackFor = Exception.class) //开启事务
    public String aliNotify(HttpServletRequest request) throws IOException {
        log.info("=============/AliNotify/authRedirect=============");
        String result = "failure";
        try {
            //获取支付宝POST过来反馈信息
            Map<String, String> params = getStringStringMap(request);
            //切记alipaypublickey是支付宝的公钥，请去open.alipay.com对应应用下查看。
            //boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String sign_type)
            CallBackDto mzCallBackDto = getMzCallBack(params);

            //异步通知验签
            boolean signVerified = false;

            signVerified = AlipaySignature.certVerifyV1(params,
                    AlipayConfig.appCertPublicKey,
                    AlipayConfig.CHARSET,
                    AlipayConfig.SIGNTYPE);
            if (!signVerified) {
                log.error("支付成功,异步通知验签失败!");
                return result;
            }
            log.info("支付成功,异步通知验签成功!");
            //1.验证out_trade_no 是否为商家系统中创建的订单号
            String outTradeNo = params.get("out_trade_no");
            //2.判断 total_amount 是否确实为该订单的实际金额
            String totalAmount = params.get("total_amount");
            BigDecimal decimal = new BigDecimal(totalAmount);
            //3.校验通知中的 seller_id是否为 out_trade_no 这笔单据的对应的操作方
            String sellerId = params.get("seller_id");
            if (!sellerId.equals(AlipayConfig.SELLER_ID)) {
                log.error("商家PID校验失败");
                return result;
            }
            //4.验证 app_id 是否为该商家本身
            String appId = params.get("app_id");
            if (!appId.equals(AlipayConfig.ALIPAY_APPID)) {
                log.error("app_id校验失败");
                return result;
            }
            //在支付宝的业务通知中，只有交易通知状态为 TRADE_SUCCESS 或 TRADE_FINISHED 时，支付宝才会认定为买家付款成功
            String tradeStatus = params.get("trade_status");
            if (!"TRADE_SUCCESS".equals(tradeStatus) && !"TRADE_FINISHED".equals(tradeStatus)) {
                log.error("支付未成功");
                return result;
            }
                switch (outTradeNo.substring(0, 2)) {
                case "HD":
                    updateEnrollStatus(outTradeNo, decimal, mzCallBackDto.getTradeNo());
                    break;
                case "RC":
                    updateTyFinanceStatus(outTradeNo, decimal, mzCallBackDto.getTradeNo());
                    break;
                case "RM":
                    updateVideoHotStatus(outTradeNo);
                    break;
                // 添加其他类型订单的处理
                default:
                    log.info("未处理的订单类型: {}", outTradeNo);
            }
            result = "success";
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return result;

    }




    @RequestMapping(value = "wx/authRedirect", method = RequestMethod.POST)
    @Transactional(rollbackFor = Exception.class) //开启事务
    public String wxpayNotify(HttpServletRequest request, HttpServletResponse response, @RequestBody String result) throws IOException {
        System.err.println("----------------------------------微信回调开始------------------------------------");
        WxDto wxDto = JSON.parseObject(result, WxDto.class);
        System.err.println(wxDto);
        Map<String, String> map = new HashMap<>(12);
        try {
            String timestamp = request.getHeader("Wechatpay-Timestamp");
            String nonce = request.getHeader("Wechatpay-Nonce");
            String serialNo = request.getHeader("Wechatpay-Serial");
            String signature = request.getHeader("Wechatpay-Signature");

            log.info("timestamp:{} nonce:{} serialNo:{} signature:{}", timestamp, nonce, serialNo, signature);
//            String result = HttpKit.readData(request);
            log.info("支付通知密文 {}", result);

            // 需要通过证书序列号查找对应的证书，verifyNotify 中有验证证书的序列号
            String plainText = WxPayKit.verifyNotify(serialNo, result, signature, nonce, timestamp,
                    WxPayConfig.mchKey, WxPayConfig.platformCert);
//                    mchKey, "/opt/aliKey/platform_cert.pem");
            if (StrUtil.isNotEmpty(plainText)) {
                log.info("支付通知明文 {}", plainText);
                WxPayDto wxPayDto = JSON.parseObject(plainText, WxPayDto.class);
                log.info("wxPayDto:"+wxPayDto);
                String outTradeNo = wxPayDto.getOutTradeNo();
                if ("SUCCESS".equals(wxPayDto.getTradeState())) {
                    BigDecimal decimal = new BigDecimal(wxPayDto.getAmount().getTotal())
                            .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
                    switch (outTradeNo.substring(0, 2)) {
                        case "HD":
                            updateEnrollStatus(outTradeNo, decimal, wxPayDto.getTransactionId());
                            break;
                        case "RC":
                            updateTyFinanceStatus(outTradeNo, decimal, wxPayDto.getTransactionId());
                            break;
                        case "RM":
                            updateVideoHotStatus(outTradeNo);
                            break;
                        // 添加其他类型订单的处理
                        default:
                            log.info("未处理的订单类型: {}", outTradeNo);
                    }
                } else if("REFUND.SUCCESS".equals(wxDto.getEventType())) {
                    log.info("退款成功wxPayDto:"+wxPayDto);
                    switch (outTradeNo.substring(0, 2)) {
                        case "HD":
                            updateEnrollIsCancel(outTradeNo);
                            break;
                        case "RC":
                            break;
                        case "RM":
                            break;
                        // 添加其他类型订单的处理
                        default:
                            log.info("未处理的订单类型: {}", outTradeNo);
                    }
                }else {
                    log.error("交易状态异常: {}", wxPayDto.getTradeState());
                }
                response.setStatus(200);
                map.put("code", "SUCCESS");
                map.put("message", "SUCCESS");
            } else {
                response.setStatus(500);
                map.put("code", "ERROR");
                map.put("message", "签名错误");
            }
            response.setHeader("Content-type", ContentType.JSON.toString());
            response.getOutputStream().write(JSONUtil.toJsonStr(map).getBytes(StandardCharsets.UTF_8));
            response.flushBuffer();
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.err.println("----------------------------------微信回调结束------------------------------------");
        return "success";
    }

    private void updateEnrollIsCancel(String outTradeNo) {
        Enroll enroll = enrollMapper.selectByOrderNo(outTradeNo);
        if (enroll != null && enroll.getStatus() != 3 ) {
            enroll.setStatus(3);
            enroll.setUpdateTime(new Date());

           EnrollRecord enrollRecord = enrollRecordMapper.getByEnrollId(enroll.getId());
           enrollRecord.setIsCancel(1);
            //退款后添加票中剩余数量
            TicketTypeRecord ticketTypeRecord=ticketTypeRecordMapper.selectByAId(enroll.getActivityId(), enroll.getVoteId());
            ticketTypeRecord.setRemainderNum(ticketTypeRecord.getRemainderNum()+ enroll.getVoteNum());
            ticketTypeRecordMapper.updateById(ticketTypeRecord);

           enrollRecordMapper.updateById(enrollRecord);
           enrollMapper.updateById(enroll);
        } else {
            log.error("订单不存在或已处理: {}", outTradeNo);
        }
    }

    private void updateVideoHotStatus(String outTradeNo) {
        VideoHot videoHot = videoFeignClient.selectByOrderNo(outTradeNo);
        if (videoHot != null && videoHot.getIsPaid() != 1) {
            videoHot.setIsPaid(1);
            videoHot.setUpdateTime(new Date());
            videoFeignClient.updateById(videoHot);
        } else {
            log.error("视频订单已处理或不存在: {}", outTradeNo);
        }
    }

    private void updateEnrollStatus(String outTradeNo, BigDecimal decimal, String transactionId) {
        Enroll enroll = enrollMapper.selectByOrderNo(outTradeNo);
        if (enroll != null && enroll.getStatus() != 1 && enroll.getStatus() != 9) {
            enroll.setPayTime(new Date());
            enroll.setTransaction(transactionId);
            enroll.setStatus(1);
            enroll.setUpdateTime(new Date());
            enrollMapper.updateById(enroll);
        } else {
            log.error("订单不存在或已处理: {}", outTradeNo);
        }
    }

    private void updateTyFinanceStatus(String outTradeNo, BigDecimal decimal, String transactionId) {
        TyFinance tyFinance = tyFinanceMapper.selectByOrderNo(outTradeNo);
        if (tyFinance != null && tyFinance.getStatus() != 2) {
            tyFinance.setStatus(2);
            tyFinance.setUpdateTime(new Date());
            tyFinance.setPayTime(new Date());
            tyFinance.setTransactionId(transactionId);
            tyFinanceMapper.updateById(tyFinance);

            UserBalance userBalance = userBalanceMapper.selectByUserId(tyFinance.getUserId());
            if (userBalance == null || userBalance.isEmpty()) {
                userBalance = new UserBalance();
                userBalance.setUserId(tyFinance.getUserId());
                userBalance.setType(1);
                userBalance.setTransactionId(transactionId);
                userBalance.setOrderNo(tyFinance.getOrderNo());
                userBalance.setUpBalance(decimal);
                userBalance.setBalance(decimal);
                userBalance.setCreateTime(new Date());
                userBalance.setUpdateTime(new Date());
                userBalanceMapper.insert(userBalance);
            } else {
                userBalance.setId(null);
                userBalance.setUserId(tyFinance.getUserId());
                userBalance.setType(1);
                userBalance.setTransactionId(transactionId);
                userBalance.setOrderNo(tyFinance.getOrderNo());
                userBalance.setUpBalance(decimal);
                userBalance.setBalance(userBalance.getBalance().add(decimal));
                userBalance.setCreateTime(new Date());
                userBalance.setUpdateTime(new Date());
                userBalanceMapper.insert(userBalance);
            }
        } else {
            log.error("订单已处理或不存在: {}", outTradeNo);
        }
    }

    @NotNull
    private CallBackDto getMzCallBack(Map<String, String> params) {
        CallBackDto callback = JSON.parseObject(JSON.toJSONString(params), CallBackDto.class);
        CallBackDto mzCallBackDto = new CallBackDto();
        BeanUtils.copyProperties(callback, mzCallBackDto);
        return mzCallBackDto;
    }

    @NotNull
    private Map<String, String> getStringStringMap(HttpServletRequest request) {
        Map<String, String> params = new HashMap<String, String>();
        Map<String, String[]> requestParams = request.getParameterMap();
        for (Object o : requestParams.keySet()) {
            String name = (String) o;
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            params.put(name, valueStr);
        }
        return params;
    }
}

